#ifndef     _PROC_H_
#define     _PROC_H_

#include    <stdlib.h>
#include    <string.h>
#include    <pthread.h>
#include    <util_list.h>

#define unlikely(_x_)           __builtin_expect(!!(_x_), 0)
#define likely(_x_)             __builtin_expect(!!(_x_), 1)

// It may be fierce to recover eip from the context.

// Hardware context of a flow of execution.
// Cares nothing about TLS.
// The stack space is fixed: to be set by the user when initializing runtime.
// C stands for 'context'.
struct C {
    void *esp, *ebp, *eip;
    unsigned stack_size;
    void *stack[];
};

// Each carrier thread holds a limbo context for stack frame collecting.
// The limbo keeps running, releasing a context and switch to the carrier
// context to pick up the next cothread to run (or to the main context to
// go on running).
// Limbo is thread-safe by its nature for cothreads carried by one thread go
// serially.
//
// When creating a cothread context, the final return address must be set to
// a gateway to the current carrier's limbo entrance.
//
// Essentially, we want things be done serially in one thread and parallelly
// among threads. -- Thus GCC TLS is to be used.

// Limbo context per carrier thread.
// L stands for 'limbo'.
struct L {
    void (*entry)(void);    // unused?
    struct C *cntx;
};

// We do not copy arguments - only a pointer is enough. 
// At least large-sized arguments will be accessed smoothly.

// Concurrency cothread control block.
// T stands for 'thread'.
struct T {
    void *arg;
    list_ctl_t lctl;
    struct C *cntx;
};

// Each carrier holds its own context, scheduling loop or the main flow.
// The context of main thread describes the flow of program itself, i.e, 
// the main flow.

// Carrier thread control block.
// M stands for 'machine'.
struct M {
    pthread_t tid;
    unsigned index;
    list_ctl_t queue;
    struct T *running;
    pthread_mutex_t queue_mutex;
    struct C *cntx;
    struct L *limbo;
};


#define get_limbo(_mptr_)   ((_mptr_)->limbo)

#define get_cntx(_ptr_)     ((_ptr_)->cntx)
#define get_cntx_o(_obj_)   ((_obj_).cntx)

#define running_T(_mptr_)   ((_mptr_)->running)
#define running_T_o(_mobj_) ((_mobj_).running)

#endif      // _PROC_H_
